import hashlib, os, sqlite3,time,sys
from mainui import *
from PyQt6.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox,QTreeWidgetItem
from PyQt6.QtCore import pyqtSlot,Qt,pyqtSignal, QThread


class start(QThread):
    def __init__(self, handle):
        super().__init__()
        self.handle = handle
        print(self.handle)

    def run(self):
        self.handle.traverse(self.handle.ui.path.text())

class MainWindow(QMainWindow):
    updata = pyqtSignal(str)


    def __init__(self):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.worker = start(self)
    @pyqtSlot()
    def on_start_clicked(self):
        self.worker.start()

    @pyqtSlot()
    def on_onlyone_clicked(self):
        count = self.ui.tree.topLevelItemCount()
        for i in range(count):
            mainitem = self.ui.tree.topLevelItem(i)
            childcount = mainitem.childCount()
            for n in range(childcount):
                item = mainitem.child(n).setCheckState(0,Qt.CheckState.Unchecked)
            mainitem.child(0).setCheckState(0,Qt.CheckState.Checked)
    @pyqtSlot()
    def on_choose_clicked(self):
        path = QFileDialog.getExistingDirectory(self,"选择一个目录")
        if os.path.isdir(path):
            self.ui.path.setText(path)
    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        try:
            if os.path.isfile(self.dbfile):
                os.remove(self.dbfile)
        except Exception as e:
            pass
    # 一对多字典{"G://1//1.jpg":{"md5":"156fsdf6as4e5","name":"1.jpg","suffix":"jpg","volumn":1565}
    def get_md5(self,path):
        with open(path, 'rb') as f:
            return hashlib.md5(f.read()).hexdigest()
    def hidebutton(self):
        # 隐藏按钮
        if self.ui.tree.topLevelItemCount() == 0:
            self.ui.remove.setEnabled(False)
            self.ui.keep.setEnabled(False)
            self.ui.onlyone.setEnabled(False)
    def database(self):
        # 创建或连接数据库
        self.dbfile = "filemap_{}.db".format(time.strftime("%Y%m%d%H%M%S"))
        conn = sqlite3.connect(self.dbfile)
        conn.execute('''
        CREATE TABLE FILEMAP(
        	filepath text,
        	md5 text,
        	filename text,
        	suffix text,
        	volume int
        )
        ''')
        conn.commit()
        return conn

    def traverse(self,index):
        self.ui.start.setEnabled(False)
        self.ui.path.setEnabled(False)
        self.ui.choose.setEnabled(False)

        conn = self.database()
        for round in os.walk(index):
            # 把当前目录下每一个文件记录
            prefix = round[0]
            for file in round[2]:
                filepath = os.path.join(prefix, file)
                print('\r', filepath, end='', flush=True)
                self.ui.label_2.setText(filepath)
                md5 = self.get_md5(filepath)
                volume = os.path.getsize(filepath)
                suffix = os.path.splitext(file)[-1][1:]
                conn.execute(
                    '''INSERT INTO FILEMAP (filepath,md5,filename,suffix,volume) VALUES ("{}", "{}", "{}","{}", {})'''.format(
                        filepath, md5,
                        file, suffix, volume))
                # 提交到数据库
                conn.commit()
        self.searchdu(conn)
        self.hidebutton()
        conn.close()

        try:
            if os.path.isfile(self.dbfile):
                os.remove(self.dbfile)
        except Exception as e:
            pass
        self.ui.start.setEnabled(True)
        self.ui.path.setEnabled(True)
        self.ui.choose.setEnabled(True)

    def searchdu(self,conn):
        self.ui.tree.clear()
        cur = conn.cursor()
        # 根据md5 来查重
        query = '''SELECT * FROM FILEMAP WHERE {} in\
         (SELECT {} FROM FILEMAP GROUP BY {} HAVING COUNT({}) >=2) ORDER BY {}'''.replace("{}", "md5")
        # query='''SELECT * FROM FILEMAP WHERE filepath in\
        #  (SELECT filepath FROM FILEMAP GROUP BY volume HAVING COUNT(volume) >=2)'''
        cur.execute(query)
        data = cur.fetchall()
        files_num = len(data)
        cur.execute('''SELECT * FROM FILEMAP GROUP BY {} HAVING COUNT({}) >=2 ORDER BY {}'''.replace("{}", "md5"))
        md5 = cur.fetchall()
        unique_file = len(md5)
        print(len(data))
        # 添加父节点
        for md5_p in md5:
            mainitem = QTreeWidgetItem(0)
            mainitem.setText(0, "文件大小：{}  文件类型：{}  文件md5：{}".format(str(md5_p[4]),md5_p[3],md5_p[1]))
            self.ui.tree.addTopLevelItem(mainitem)
            # self.ui.tree.setCurrentIndex(-1)
            for i in data:
                if i[1] == md5_p[1]:
                    print(i)
                    # 添加行
                    item = QTreeWidgetItem(1)
                    item.setText(0,i[0])
                    item.setText(1,i[2])
                    item.setText(2,i[1])
                    item.setText(3,i[3])
                    item.setText(4,str(i[4]))
                    # item.setFlags((Qt.ItemIsSelectable | Qt.ItemIsUserCheckable  | Qt.ItemIsEnabled | Qt.ItemIsAutoTristate))
                    item.setCheckState(0,Qt.CheckState.Unchecked)
                    mainitem.addChild(item)
        info = '''共检查到{}项可能重复文件，根据md5校验出{}项独特的文件'''.format(files_num,unique_file)
        self.ui.label_2.setText(info)
        if self.ui.tree.topLevelItemCount():
            self.ui.tree.expandAll()
            self.ui.remove.setEnabled(1)
            self.ui.keep.setEnabled(1)
            self.ui.onlyone.setEnabled(1)


    @pyqtSlot()
    def on_remove_clicked(self):
        if QMessageBox.question(self, "重要提示！", "是否确定删除所有选择的文件，请仔细核对。该操作无法撤回！！",
                                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.Yes) == QMessageBox.StandardButton.No:
            QMessageBox.information(self,"通知", "取消操作")
            return 0
        remove_list = []
        count = self.ui.tree.topLevelItemCount()
        offset = 0
        for i in range(count):
            mainitem = self.ui.tree.topLevelItem(i-offset)
            self.deeptree_remove(mainitem,remove_list)
            if mainitem.childCount() <= 1:
                # 子节点小于等于1，清除父节点
                self.ui.tree.takeTopLevelItem(i-offset)
                offset+=1

        print(remove_list)
        self.ui.label_2.setText('''已删除{}项重复文件'''.format(len(remove_list)))
        self.hidebutton()

    def deeptree_remove(self,mainitem,remove_list):
        count = mainitem.childCount()
        offset = 0
        for i in range(count):
            item = mainitem.child(i-offset)
            if item.checkState(0) == Qt.CheckState.Checked:
                offset+=1
                os.remove(item.text(0))
                item.parent().removeChild(item)
                remove_list.append(item.text(0))

    def deeptree_keep(self,mainitem,remove_list):
        count = mainitem.childCount()
        offset = 0
        for i in range(count):
            item = mainitem.child(i-offset)
            if item.checkState(0) == Qt.CheckState.Unchecked:
                offset+=1
                os.remove(item.text(0))
                item.parent().removeChild(item)
                remove_list.append(item.text(0))

    @pyqtSlot()
    def on_keep_clicked(self):
        if QMessageBox.question(self, "重要提示！", "是否确定仅保留所选文件，请仔细核对。该操作无法撤回！！",
                                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.Yes) == QMessageBox.StandardButton.No:
            QMessageBox.information(self,"通知", "取消操作")
            return 0
        remove_list = []
        count = self.ui.tree.topLevelItemCount()
        offset = 0
        for i in range(count):
            mainitem = self.ui.tree.topLevelItem(i-offset)
            self.deeptree_keep(mainitem, remove_list)
            if mainitem.childCount() <= 1:
                # 子节点小于等于1，清除父节点
                self.ui.tree.takeTopLevelItem(i-offset)
                offset += 1
        print(remove_list)
        self.ui.label_2.setText('''已删除{}项重复文件'''.format(len(remove_list)))
        self.hidebutton()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mywin = MainWindow()
    mywin.show()
    sys.exit(app.exec())